home *** CD-ROM | disk | FTP | other *** search
- /*P*/
- /****************************************************************/
- /* */
- /* backgammon */
- /* */
- /* This is a program to play backgammon with the user. The */
- /* board is displayed from a "top view", and has numbers */
- /* surrounding the points. The system will automatically roll */
- /* the dice for you, and makes its own moves according to some */
- /* simple evaluations. */
- /* */
- /* It is assumed that you know how to play backgammon. This */
- /* program will play either as white, or as black; this is an */
- /* option you select. Unlike some variations of backgammon, */
- /* each game is played in the same direction (according to the */
- /* rules, this is correct - some people reverse on every-other */
- /* game). In order to run the program, you just type in "bkg". */
- /* A keystroke sets the internal random number generation. You */
- /* specify either white or black at this time. */
- /* */
- /* The program prompts you to "Return to roll: ". Just pressing */
- /* a return character rolls the dice, and you may then make a */
- /* move. Moves are specified by a simple method - you type the */
- /* number of the point to move from, a slash, and the number */
- /* of points to move. For example, if you rolled a 4 and a 6, */
- /* and you have players on points 12 and 7, you might play */
- /* something like "7/6 12/4", or "12/6 7/4", or even "12/6/4" */
- /* or "7/4/6", etc... Note that you must obey the rules - no */
- /* point that is occupied by >= 2 of the opponents men can be */
- /* landed on, etc. */
- /* */
- /* When you or the opponent are "hit", a man is placed on the */
- /* bar in the middle. You can move off of the bar by using a */
- /* "b" in place of the source point, like: "b/3 13/5". You can */
- /* also use the numbers 0 and 25 for the bar, if you like. */
- /* */
- /* Doubling is supported. The box on the bar with a '1' in it */
- /* is the doubling cube. When you want to double, wait for the */
- /* "Return to roll: " message, then type "double" or "d". Also, */
- /* the computer may double you, in which case you need to */
- /* decide whether or not to accept. Again, familiarity with the */
- /* rules of the game will help on this... */
- /* */
- /* Lastly, you can type "quit" in place of "double" to get out */
- /* quick when the boss shows up. */
- /* */
- /* Author: Bill Mahoney */
- /* 1819 North 66th Street */
- /* Omaha, Nebraska 68104 */
- /* (402) 554-0312 */
- /* */
- /* Date: Misc. 1986 */
- /* */
- /* Copyright: 1986, Mahoney */
- /* */
- /****************************************************************/
-
- #define MAIN
- #include <stdio.h>
- #include "bkg.h"
-
- /*P*/
- /****************************************************************/
- /* */
- /* main */
- /* */
- /* There are sume undocumented features here. Ok, ok, so now */
- /* they aren't undocumented anymore! For testing, you can give */
- /* a "-g" option, and play many many games. This is used to */
- /* test out new evaluation strategy against old. A "-d" lets */
- /* you use "debug" instead of "double" or "quit". See that */
- /* section for debugging commands. */
- /* */
- /****************************************************************/
-
- main( ac, av )
-
- int ac;
- char *av[];
-
- {
-
- char ch;
- int i, j, games, played, white, black;
- int c_white, c_black, side;
- int value, on_board;
-
- games = 0;
- white = black = 0;
- k10 = FALSE;
-
- for( i = 1; i < ac; i++ )
- if ( av[ i ][ 0 ] == '-' )
- switch( toupper( av[ i ][ 1 ] ) )
- {
-
- case 'D': debug++;
- break;
-
- case 'G': sscanf( av[ ++i ], "%d", &games );
- break;
-
- case 'R': r_test++;
- break;
-
- default: printf( "Usage: bkg\n" );
- exit( 0 );
- break;
-
- } /* end args */
- else
- {
- printf( "Usage: bkg\n" );
- exit( 0 );
- }
-
- /* The BDS compiler on the Kaypro does not support initialized */
- /* arrays, so we have to do it ourselves here. This is a tbl */
- /* for probability of being able to move <subscript> points */
- /* based on the possible 36 combinations. */
-
- prob[ 1 ] = 11; prob[ 2 ] = 12; prob[ 3 ] = 13; prob[ 4 ] = 14;
- prob[ 5 ] = 15; prob[ 6 ] = 16; prob[ 7 ] = 6; prob[ 8 ] = 7;
- prob[ 9 ] = 5; prob[ 10 ] = 3; prob[ 11 ] = 2; prob[ 12 ] = 3;
- prob[ 13 ] = 0; prob[ 14 ] = 0; prob[ 15 ] = 1; prob[ 16 ] = 1;
- prob[ 17 ] = 0; prob[ 18 ] = 1; prob[ 19 ] = 0; prob[ 20 ] = 1;
- prob[ 21 ] = 0; prob[ 22 ] = 0; prob[ 23 ] = 0; prob[ 24 ] = 1;
-
- if ( ! games )
- {
-
- puts( "\nBackgammon, By Bill Mahoney" );
- srand1( "\nPress any Key: " );
- if ( getchar() != '\n' )
- putchar( '\n' );
-
- printf( "Will you be playing white, or black? " );
- do {
- ch = toupper( raw_keyboard() );
- } while ( ( ch != 'B' ) &&
- ( ch != 'W' ) );
-
- if ( ch == 'W' )
- {
- puts( "White\n" );
- side = TRUE;
- c_black = TRUE;
- c_white = FALSE;
- }
- else
- {
- puts( "Black\n" );
- side = FALSE;
- c_white = TRUE;
- c_black = FALSE;
- }
- }
- else
- {
- srand( games );
- side = FALSE;
- c_white = c_black = TRUE;
- }
-
- for( i = 0; i < SIZE; i++ )
- board[ i ][ BLACK ] = board[ i ][ WHITE ] = board[ i ][ 2 ] = 0;
-
- played = 0;
-
- do {
-
- /* Play a game. The play routine returns an */
- /* indication of just who it was that won. */
-
- if ( play( c_white, c_black, white, black, side, &value, played ) )
- {
-
- /* A "true" return is a win for black. */
- /* But it may be by way of a "quit" or */
- /* a double, so check to see if all */
- /* his men are off. */
-
- for( on_board = 0, i = B_BAR; i < 25; i++ )
- on_board += board[ i ][ BLACK ];
-
- for( i = W_BAR; i > 18; i-- )
- if ( board[ i ][ WHITE ] )
- break;
-
- /* Check for the "odd" types of wins. */
-
- if ( ( i > 18 ) &&
- ( ! on_board ) )
- {
- black += ( 3 * value );
- write_at( 23, 0, "Black wins a backgammon! Another game? ", TEXT_COLOR );
- }
- else
- {
-
- for( j = 0; i; i-- )
- j += board[ i ][ WHITE ];
-
- if ( ( j == 15 ) &&
- ( ! on_board ) )
- {
- black += ( 2 * value );
- write_at( 23, 0, "Black wins a gammon! Another game? ", TEXT_COLOR );
- }
- else
- {
- black += value;
- write_at( 23, 0, "Black wins. Another game? ", TEXT_COLOR );
- }
-
- } /* not a backgammon */
-
- } /* black wins */
-
- else
- {
-
- for( on_board = 0, i = W_BAR; i; i-- )
- on_board += board[ i ][ WHITE ];
-
- for( i = B_BAR; i < 7; i++ )
- if ( board[ i ][ BLACK ] )
- break;
-
- /* Again, check for "odd" wins */
-
- if ( ( i < 7 ) &&
- ( ! on_board ) )
- {
- white += ( 3 * value );
- write_at( 23, 0, "White wins a backgammon! Another game? ", TEXT_COLOR );
- }
- else
- {
-
- for( j = 0; i < 25; i++ )
- j += board[ i ][ BLACK ];
-
- if ( ( j == 15 ) &&
- ( ! on_board ) )
- {
- white += ( 2 * value );
- write_at( 23, 0, "White wins a gammon! Another game? ", TEXT_COLOR );
- }
- else
- {
- white += value;
- write_at( 23, 0, "White wins. Another game? ", TEXT_COLOR );
- }
-
- } /* not a backgammon */
-
- } /* white wins */
-
- played++;
-
- /* Keep on doing more games until we */
- /* use up the play limit, or the guy */
- /* has had enough laughter for today. */
-
- } while ( ( ( games ) && ( games != played ) ) ||
- ( toupper( raw_keyboard() ) == 'Y' ) );
-
- clear();
- printf( "Played %d game(s), white wins %d, black wins %d\n", played, white, black );
-
- } /* main */
-
- /*P*/
- /****************************************************************/
- /* */
- /* play */
- /* */
- /* This function will take turns allowing each player to make a */
- /* move. Since the computer can play either side, or both, we */
- /* check when it is a players turn to move, and either call the */
- /* "human type" parser, or the computer move generator. If the */
- /* latter is the case, then the move generator will give us */
- /* back a string in the same format as if a human typed it - or */
- /* something like "4/3 5/6", whatever. We then pass this on to */
- /* the parser routine. */
- /* */
- /* After each move, we scan the board to make sure that we can */
- /* still play. If not, then somebody one, and we're outa here. */
- /* */
- /****************************************************************/
-
- play( c_white, c_black, w_wins, b_wins, side, value, played )
-
- int c_white, c_black, w_wins, b_wins, side, *value, played;
-
- {
-
- char temp[ 80 ], line[ 80 ], ch;
- int i, j, temp1, temp2, b_count, w_count;
- int die_1, die_2, owned, winner;
- int biggest, column, first_play;
-
- /* Put up the board, put the */
- /* double cube on it, then go. */
-
- draw( side );
- show_cube( NOBODY, 1, side );
- *value = 1;
- winner = owned = NOBODY;
- first_play = TRUE;
-
- /* re-initialize the board, in */
- /* case we are playing game #2 */
-
- for( i = 0; i < 26; i++ )
- board[ i ][ WHITE ] = board[ i ][ BLACK ] = board[ i ][ 2 ] = 0;
-
- /* initialize the pieces on it. */
-
- for( i = 0; i < 5; i++ )
- {
-
- move_piece( -1, 6, WHITE, side );
- if ( i < 3 )
- move_piece( -1, 8, WHITE, side );
- move_piece( -1, 13, WHITE, side );
- if ( i < 2 )
- move_piece( -1, 24, WHITE, side );
-
- if ( i < 2 )
- move_piece( -1, 1, BLACK, side );
- move_piece( -1, 12, BLACK, side );
- if ( i < 3 )
- move_piece( -1, 17, BLACK, side );
- move_piece( -1, 19, BLACK, side );
-
- }
-
- /* While testing, we keep tabs on how */
- /* we're doing with b_eval vs w_eval */
-
- if ( played )
- {
- sprintf( temp, "Played %d games, white wins %d, black wins %d.", played, w_wins, b_wins );
- write_at( X_PROMPT + 3, Y_PROMPT, temp, TEXT_COLOR );
- }
-
- /* decide who starts. This is different */
- /* than a regular roll, because each */
- /* player rolls one dice, and whatever */
- /* numbers are up, we use. */
-
- do {
-
- for( i = 0; i <= 25; i++ )
- show_die( 1, ( die_1 = ( rand() % 6 ) + 1 ) );
- sprintf( temp, "White rolls a %d.", die_1 );
- write_at( X_INFO, Y_INFO, temp, TEXT_COLOR );
-
- for( i = 0; i <= 25; i++ )
- show_die( 0, ( die_2 = ( rand() % 6 ) + 1 ) );
- sprintf( temp, "Black rolls a %d.", die_2 );
- write_at( X_INFO + 1, Y_INFO, temp, TEXT_COLOR );
-
- } while ( die_1 == die_2 );
-
- /* who won? let the user know */
-
- if ( die_1 > die_2 )
- {
- me = WHITE;
- sprintf( temp, "%cWhite starts with a %d, %d", CTEOL, die_1, die_2 );
- write_at( X_INFO, Y_INFO, temp, TEXT_COLOR );
- column = strlen( temp );
- }
- else
- {
- me = BLACK;
- sprintf( temp, "%cBlack starts with a %d, %d", CTEOL, die_1, die_2 );
- write_at( X_INFO + 1, Y_INFO, temp, TEXT_COLOR );
- column = strlen( temp );
- }
-
- /* play until someone wins the game */
-
- while( TRUE )
- {
-
- /* Play each person in turn. */
-
- if ( me == BLACK )
- {
-
- /* Just because it is his turn */
- /* does not always mean he can */
- /* take it... */
-
- if ( can_move( BLACK ) )
- {
-
- if ( ! first_play )
- {
-
- if ( c_black )
- {
-
- /* Should we double? Check it. */
-
- get_pre_command( BLACK, line, owned, *value );
- if ( ! pre_command( line, &owned, value, side, me, &winner, &die_1, &die_2, c_black, c_white ) )
- exit( printf( "%cplay: panic: pre_command is %s\n", 0x07, line ) );
- }
- else
- do {
-
- /* Those damn humans are playing again. */
- /* I wore out this code - I always play */
- /* black. */
-
- char_at( X_INFO + 2, Y_INFO, CTEOL, TEXT_COLOR );
- write_at( X_INFO + 2, Y_INFO, "Return to roll: ", TEXT_COLOR );
- gets( line, 79 );
-
- } while ( ! pre_command( line, &owned, value, side, me, &winner,
- &die_1, &die_2, c_black, c_white ) );
-
- if ( winner != NOBODY )
- return( winner );
-
- roll( &die_1, &die_2, &column );
- if ( die_1 == die_2 )
- sprintf( temp, "%cBlack rolls double %d's", CTEOL, die_1 );
- else
- sprintf( temp, "%cBlack rolls a %d and a %d", CTEOL, die_1, die_2 );
- write_at( X_INFO + 1, Y_INFO, temp, TEXT_COLOR );
-
- }
-
- /* We generate a computer move, so we */
- /* can see how many moves are allowed. */
- /* You must make as many as you can, no */
- /* matter what trouble it causes. */
-
- b_movegen( die_1, die_2, FALSE, &biggest, line, FALSE );
-
- if ( biggest )
- {
-
- if ( c_black )
- {
-
- if ( first_play )
- first( die_1, die_2, BLACK, line );
- else
- b_movegen( die_1, die_2, TRUE, &biggest, line, FALSE );
-
- sprintf( temp, " and moves %s", line );
- write_at( X_INFO + 1, column, temp, TEXT_COLOR );
- if ( ! handle_command( die_1, die_2, line, biggest, side ) )
- exit( printf( "%cplay: panic: computer move %s\n", 0x07, line ) );
-
- } /* computer move */
- else
- do {
-
- char_at( X_INFO + 2, Y_INFO, CTEOL, TEXT_COLOR );
- write_at( X_INFO + 2, Y_INFO, "Your move: ", TEXT_COLOR );
- gets( line, 79 );
-
- } while ( ! handle_command( die_1, die_2, line, biggest, side ) );
-
- } /* can move */
- else
- write_at( X_INFO + 1, column, " and can not move.", ALERT_COLOR );
-
- } /* can move */
- else
- {
- char_at( X_INFO + 1, Y_INFO, CTEOL, TEXT_COLOR );
- write_at( X_INFO + 1, Y_INFO, "Black can not play.", ALERT_COLOR );
- }
-
- } /* black */
- else
- {
-
- /* This section is exactly the */
- /* same, but it handles white. */
-
- if ( can_move( WHITE ) )
- {
-
- if ( ! first_play )
- {
-
- if ( c_white )
- {
- get_pre_command( WHITE, line, owned, *value );
- if ( ! pre_command( line, &owned, value, side, me, &winner, &die_1, &die_2, c_black, c_white ) )
- exit( printf( "%cplay: panic: pre_command is %s\n", 0x07, line ) );
- }
- else
- do {
-
- char_at( X_INFO + 2, Y_INFO, CTEOL, TEXT_COLOR );
- write_at( X_INFO + 2, Y_INFO, "Return to roll: ", TEXT_COLOR );
- gets( line, 79 );
-
- } while ( ! pre_command( line, &owned, value, side, me, &winner,
- &die_1, &die_2, c_black, c_white ) );
-
- if ( winner != NOBODY )
- return( winner );
-
- roll( &die_1, &die_2, &column );
- if ( die_1 == die_2 )
- sprintf( temp, "%cWhite rolls double %d's", CTEOL, die_1 );
- else
- sprintf( temp, "%cWhite rolls a %d and a %d", CTEOL, die_1, die_2 );
- write_at( X_INFO, Y_INFO, temp, TEXT_COLOR );
-
- } /* first play */
-
- w_movegen( die_1, die_2, FALSE, &biggest, line, FALSE );
-
- if ( biggest )
- {
-
- if ( c_white )
- {
-
- if ( first_play )
- first( die_1, die_2, WHITE, line );
- else
- w_movegen( die_1, die_2, TRUE, &biggest, line, FALSE );
-
- sprintf( temp, " and moves %s", line );
- write_at( X_INFO, column, temp, TEXT_COLOR );
- if ( ! handle_command( die_1, die_2, line, biggest, side ) )
- exit( printf( "%cplay: panic: computer move %s\n", 0x07, line ) );
-
- } /* computer move */
- else
- do {
-
- char_at( X_INFO + 2, Y_INFO, CTEOL, TEXT_COLOR );
- write_at( X_INFO + 2, Y_INFO, "Your move: ", TEXT_COLOR );
- gets( line, 79 );
-
- } while ( ! handle_command( die_1, die_2, line, biggest, side ) );
-
-
- } /* can move */
- else
- write_at( X_INFO, column, " and can not move.", ALERT_COLOR );
-
- } /* can move */
- else
- {
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- write_at( X_INFO, Y_INFO, "White can not play.", ALERT_COLOR );
- }
-
- } /* white */
-
- first_play = FALSE;
-
- /* do we have a winner? */
-
- for( b_count = 0, i = B_BAR; i < 25; i++ )
- b_count += board[ i ][ BLACK ];
-
- if ( ! b_count )
- return( BLACK );
-
- for( w_count = 0, i = W_BAR; i; i-- )
- w_count += board[ i ][ WHITE ];
-
- if ( ! w_count )
- return( WHITE );
-
- /* swap players, and re-roll the dice */
- me = ( me == WHITE ? BLACK : WHITE );
-
- } /* while true */
-
- } /* play */
-
- /*P*/
- /****************************************************************/
- /* */
- /* first */
- /* */
- /* This routine looks up the best first move for a given */
- /* player. The first roll in backgammon generally has an */
- /* accepted "best" thing to do. After that, it's up to the */
- /* algorithm and eval. */
- /* */
- /****************************************************************/
-
- first( d1, d2, who, buf )
-
- int d1, d2, who;
- char *buf;
-
- {
-
- int temp, i;
- struct {
- int hi, low;
- char *move[ 2 ];
- } tbl[ 21 ];
-
- /* I hate having to do this at runtime. Anyway, this is a */
- /* table of best "first moves" given two rolls of the dice. */
- /* There are 21 possible unique combinations. This REALLY needs */
- /* to be fixed in the BDS compiler. */
-
- tbl[ 0 ].hi = 6; tbl[ 0 ].low = 5;
- tbl[ 0 ].move[ BLACK ] = "1/6/5";
- tbl[ 0 ].move[ WHITE ] = "24/6/5";
-
- tbl[ 1 ].hi = 6; tbl[ 1 ].low = 4;
- tbl[ 1 ].move[ BLACK ] = "1/6/4";
- tbl[ 1 ].move[ WHITE ] = "24/6/4";
-
- tbl[ 2 ].hi = 6; tbl[ 2 ].low = 3;
- tbl[ 2 ].move[ BLACK ] = "1/6 12/3";
- tbl[ 2 ].move[ WHITE ] = "24/6 13/3";
-
- tbl[ 3 ].hi = 6; tbl[ 3 ].low = 2;
- tbl[ 3 ].move[ BLACK ] = "1/6 12/2";
- tbl[ 3 ].move[ WHITE ] = "24/6 13/2";
-
- tbl[ 4 ].hi = 6; tbl[ 4 ].low = 1;
- tbl[ 4 ].move[ BLACK ] = "12/6 17/1";
- tbl[ 4 ].move[ WHITE ] = "13/6 8/1";
-
- tbl[ 5 ].hi = 5; tbl[ 5 ].low = 4;
- tbl[ 5 ].move[ BLACK ] = "12/5 12/4";
- tbl[ 5 ].move[ WHITE ] = "13/5 13/4";
-
- tbl[ 6 ].hi = 5; tbl[ 6 ].low = 3;
- tbl[ 6 ].move[ BLACK ] = "19/3 17/5";
- tbl[ 6 ].move[ WHITE ] = "6/3 8/5";
-
- tbl[ 7 ].hi = 5; tbl[ 7 ].low = 2;
- tbl[ 7 ].move[ BLACK ] = "12/5 12/2";
- tbl[ 7 ].move[ WHITE ] = "13/5 13/2";
-
- tbl[ 8 ].hi = 5; tbl[ 8 ].low = 1;
- tbl[ 8 ].move[ BLACK ] = "1/1 12/5";
- tbl[ 8 ].move[ WHITE ] = "24/1 13/5";
-
- tbl[ 9 ].hi = 4; tbl[ 9 ].low = 3;
- tbl[ 9 ].move[ BLACK ] = "12/4 12/3";
- tbl[ 9 ].move[ WHITE ] = "13/4 13/3";
-
- tbl[ 10 ].hi = 4; tbl[ 10 ].low = 2;
- tbl[ 10 ].move[ BLACK ] = "19/2 17/4";
- tbl[ 10 ].move[ WHITE ] = "6/2 8/4";
-
- tbl[ 11 ].hi = 4; tbl[ 11 ].low = 1;
- tbl[ 11 ].move[ BLACK ] = "12/4 1/1";
- tbl[ 11 ].move[ WHITE ] = "13/4 24/1";
-
- tbl[ 12 ].hi = 3; tbl[ 12 ].low = 2;
- tbl[ 12 ].move[ BLACK ] = "12/3 12/2";
- tbl[ 12 ].move[ WHITE ] = "13/3 13/2";
-
- tbl[ 13 ].hi = 3; tbl[ 13 ].low = 1;
- tbl[ 13 ].move[ BLACK ] = "19/1 17/3";
- tbl[ 13 ].move[ WHITE ] = "6/1 8/3";
-
- tbl[ 14 ].hi = 2; tbl[ 14 ].low = 1;
- tbl[ 14 ].move[ BLACK ] = "12/2 1/1";
- tbl[ 14 ].move[ WHITE ] = "13/2 24/1";
-
- tbl[ 15 ].hi = 6; tbl[ 15 ].low = 6;
- tbl[ 15 ].move[ BLACK ] = "12/6 12/6 1/6 1/6";
- tbl[ 15 ].move[ WHITE ] = "13/6 13/6 24/6 24/6";
-
- tbl[ 16 ].hi = 5; tbl[ 16 ].low = 5;
- tbl[ 16 ].move[ BLACK ] = "12/5/5 12/5/5";
- tbl[ 16 ].move[ WHITE ] = "13/5/5 13/5/5";
-
- tbl[ 17 ].hi = 4; tbl[ 17 ].low = 4;
- tbl[ 17 ].move[ BLACK ] = "1/4 1/4 12/4 12/4";
- tbl[ 17 ].move[ WHITE ] = "24/4 24/4 13/4 13/4";
-
- tbl[ 18 ].hi = 3; tbl[ 18 ].low = 3;
- tbl[ 18 ].move[ BLACK ] = "19/3 19/3 17/3 17/3";
- tbl[ 18 ].move[ WHITE ] = "6/3 6/3 8/3 8/3";
-
- tbl[ 19 ].hi = 2; tbl[ 19 ].low = 2;
- tbl[ 19 ].move[ BLACK ] = "12/2 12/2 19/2 19/2";
- tbl[ 19 ].move[ WHITE ] = "13/2 13/2 6/2 6/2";
-
- tbl[ 20 ].hi = 1; tbl[ 20 ].low = 1;
- tbl[ 20 ].move[ BLACK ] = "19/1 19/1 17/1 17/1";
- tbl[ 20 ].move[ WHITE ] = "6/1 6/1 8/1 8/1";
-
- /* Now FINALLY we can get something done. */
-
- if ( d1 < d2 )
- {
- temp = d1; d1 = d2; d2 = temp;
- }
-
- for( i = 0; i < 21; i++ )
- if ( ( tbl[ i ].hi == d1 ) &&
- ( tbl[ i ].low == d2 ) )
- {
- strcpy( buf, tbl[ i ].move[ who ] );
- break;
- }
-
- if ( i == 21 )
- exit( printf( "first: panic: die %d, %d who %d", d1, d2, who ) );
-
- } /* first */
-
- /*P*/
- /****************************************************************/
- /* */
- /* pre_command */
- /* */
- /* Handle special commands in here. These include quitting and */
- /* doubling. This section also handles the debug commands. */
- /* Since these change as requirements for info do, just look at */
- /* the specifics below for more info. Note, though, that the */
- /* doubling cube is "owned" - no one player is allowed to use */
- /* it twice in a row. We've got ta check that. */
- /* */
- /****************************************************************/
-
- pre_command( line, owned, value, side, who, winner, die_1, die_2, c_black, c_white )
-
- char line[];
- int *owned, *value, side, who, *winner;
- int *die_1, *die_2, c_black, c_white;
-
- {
-
- char ch, accept();
- int i, j, temp1, temp2;
-
- *winner = NOBODY;
-
- for( i = 0; line[ i ]; i++ )
- line[ i ] = tolower( line[ i ] );
-
- /* This is the easy case - we just want to go */
- /* ahead and roll the dice. */
-
- if ( ( ! strcmp( line, "roll" ) ) ||
- ( ! strcmp( line, "" ) ) )
- return( TRUE );
-
- /* Handle the quit command if the user wants */
- /* out (the boss is coming! - Bruce?) */
-
- if ( ( ! strcmp( line, "q" ) ) ||
- ( ! strcmp( line, "quit" ) ) )
- {
-
- char_at( X_INFO + 2, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "Do you really want to quit? " );
-
- if ( toupper( raw_keyboard() ) == 'Y' )
- {
- *winner = ( who == BLACK ) ? WHITE : BLACK;
- return( TRUE );
- }
- else
- {
- char_at( X_INFO + 2, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "Well ok then!" );
- line[ 0 ] = '\0';
- return( FALSE );
- }
-
- } /* quit */
-
- /* Handle the doubling cube here. Only allow a */
- /* double if you own the cube right now. */
-
- if ( ( ! strcmp( line, "double" ) ) ||
- ( ! strcmp( line, "dbl" ) ) ||
- ( ! strcmp( line, "d" ) ) )
- {
-
- /* The cube only goes up to 64, so we */
- /* check it. (The real reason is that */
- /* it does not display right as 3 */
- /* digits, but...) */
-
- if ( *value == 64 )
- {
- write_at( X_INFO + ( who == WHITE ? 0 : 1 ), Y_INFO,
- "The doubling cube only goes up to 64.", TEXT_COLOR );
- return( FALSE );
- } /* 64 check */
-
- if ( *owned != ( ( who == BLACK ) ? WHITE : BLACK ) )
- {
-
- if ( who == BLACK )
- {
- char_at( X_INFO + 1, Y_INFO, CTEOL, TEXT_COLOR );
- write_at( X_INFO + 1, Y_INFO, "Black doubles. Do you accept? ", TEXT_COLOR );
- if ( c_white )
- ch = accept( WHITE );
- else
- do ch = toupper( raw_keyboard() );
- while ( ( ch != 'N' ) &&
- ( ch != 'Y' ) );
- }
- else
- {
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- write_at( X_INFO, Y_INFO, "White doubles. Do you accept? ", TEXT_COLOR );
- if ( c_black )
- ch = accept( BLACK );
- else
- do ch = toupper( raw_keyboard() );
- while ( ( ch != 'N' ) &&
- ( ch != 'Y' ) );
- }
-
- if ( ch == 'Y' )
- {
- printf( " Yes." );
- *value *= 2;
- *owned = ( who == WHITE ) ? BLACK : WHITE;
- show_cube( *owned, *value, side );
- line[ 0 ] = '\0';
- return( TRUE );
- }
- else
- {
- printf( " No." );
- *winner = who;
- return( TRUE );
- }
-
- } /* owned */
-
- else
- write_at( X_INFO + ( who == WHITE ? 0 : 1 ), Y_INFO,
- "You do not have control of the doubling cube.", TEXT_COLOR );
-
- } /* double */
-
- /* We check all sorts of debugging stuff here, thus */
- /* enabling the user to change the board all up, etc. */
-
- if ( ! strcmp( line, "debug" ) )
- {
- debug = ( ++debug % 4 );
- sprintf( line, "debug = %d%c", debug, CTEOL );
- write_at( X_INFO, Y_INFO, line, ALERT_COLOR );
- }
-
- if ( ! strcmp( line, "load" ) )
- {
-
- for( i = 0; i < 26; i++ )
- board[ i ][ WHITE ] = board[ i ][ BLACK ] = board[ i ][ 2 ] = 0;
-
- draw( side );
-
- while ( TRUE )
- {
-
- sprintf( line, "%cpoint white black: ", CTEOL );
- write_at( X_INFO, Y_INFO, line, ALERT_COLOR );
- gets( line, 79 );
- if ( ! line[ 0 ] )
- break;
-
- sscanf( line, "%d %d %d", &i, &temp1, &temp2 );
- for( j = 0; j < temp1; j++ )
- move_piece( -1, i, WHITE, side );
- for( j = 0; j < temp2; j++ )
- move_piece( -1, i, BLACK, side );
-
- } /* read loop */
-
- } /* load */
-
- if ( ! strncmp( line, "forceroll", 9 ) )
- {
- sscanf( &line[ 10 ], "%d %d", &die_1, &die_2 );
- show_die( 1, die_1 );
- show_die( 0, die_2 );
- }
-
- if ( ! strcmp( line, "dump" ) )
- {
-
- for( i = 0; i < 3; i++ )
- {
- char_at( 21 + i, 0, CTEOL );
- for( j = 0; j < 26; j++ )
- printf( "%02d ", board[ j ][ i ] );
- }
-
- } /* dump */
-
- return( FALSE );
-
- } /* pre_command */
-
- /*P*/
- /****************************************************************/
- /* */
- /* handle_command */
- /* */
- /* Take a command string from the terminal, and chop it up so */
- /* that it moves the pieces around on the board. Commands have */
- /* the form: "4/5 18/3" - that would move the guy at point 4 */
- /* 5 spaces, and the guy at 18 3 spaces. The variable */
- /* "required" indicates how many moves must be made. This can */
- /* range from 1 up to 4 (doubles). The player must make the */
- /* right number of moves. */
- /* */
- /****************************************************************/
-
- handle_command( die_1, die_2, line, required, side )
-
- int die_1, die_2;
- char line[];
- int required, side;
-
- {
-
- char save[ 80 ];
- char msg[ 32 ], ch;
- int test[ SIZE ][ 3 ], s_val, d_val, temp1, temp2;
- int s_psn, l_psn, done, i, j, roll_used[ 2 ];
- int start[ 5 ], dist[ 5 ], target[ 5 ];
-
- s_val = d_val = 0;
- s_psn = l_psn = 0;
- done = FALSE;
-
- /* until the end of line, or a maximum */
- /* of 4 moves, do */
-
- while( ( ! done ) &&
- ( s_val <= 4 ) )
- {
-
- /* move bytes into "save" until */
- /* a slash is found, then do it */
-
- if ( isdigit( line[ l_psn ] ) )
- save[ s_psn++ ] = line[ l_psn ];
- else
- switch( tolower( line[ l_psn ] ) )
- {
-
- case '/': /* end of start area, or */
- /* second distance */
- if ( s_val == ( d_val + 1 ) )
- {
- /* A command like "14/3/5" */
-
- save[ s_psn ] = '\0';
- sscanf( save, "%d", &dist[ d_val++ ] );
- s_psn = 0;
-
- if ( me == WHITE )
- start[ s_val ] = start[ s_val - 1 ] -
- dist[ d_val - 1 ];
- else
- start[ s_val ] = start[ s_val - 1 ] +
- dist[ d_val - 1 ];
- s_val++;
-
- }
-
- else
- {
- /* it is a start */
- save[ s_psn ] = '\0';
- sscanf( save, "%d", &start[ s_val++ ] );
- s_psn = 0;
- }
- break;
-
- case ' ': /* end of length spec */
- save[ s_psn ] = '\0';
- sscanf( save, "%d", &dist[ d_val++ ] );
- s_psn = 0;
- break;
-
- case '\0': /* end of length spec, */
- /* and end of line. */
- if ( l_psn == 0 )
- return( FALSE );
- save[ s_psn ] = '\0';
- sscanf( save, "%d", &dist[ d_val++ ] );
- s_psn = 0;
- done++;
- break;
-
- case 'b': /* bar is source - note that */
- /* it should always be followed */
- /* by a slash. */
- start[ s_val++ ] = BAR;
- l_psn++; /* eat '/' */
- break;
-
- default: char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "I didn't understand that!" );
- return( FALSE );
- break;
-
- } /* switch */
-
- /* parser checking stuff... */
-
- if ( debug > 3 )
- {
-
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "Column = %d s_val = %d d_val = %d starts = ",
- l_psn, s_val, d_val );
- for( i = 0; i < s_val; i++ )
- printf( "%d ", start[ i ] );
- printf( "dists = " );
- for( i = 0; i < d_val; i++ )
- printf( "%d ", dist[ i ] );
- raw_keyboard();
-
- } /* debug */
-
- l_psn++;
-
- } /* not done */
-
- /* obviously, there should be the same number of start */
- /* places as there are distances. If not, error! */
-
- if ( s_val != d_val )
- {
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "I did not understand that!" );
- return( FALSE );
- }
-
- /* The user must supply as many moves as he/she can. */
- /* for example, if you can make 4 moves, even if one of */
- /* them would be a strategic disaster, you must still */
- /* make all four of the moves. */
-
- if ( s_val != required )
- {
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "You must make %d %s.", required, ( required > 1 ? "moves" : "move" ) );
- return( FALSE );
- }
-
- /* make a test copy of the current game status */
-
- movmem( board, test, BOARD_IN_BYTES );
-
- /* Zero out the roll_used array so that we can check it */
-
- roll_used[ 0 ] = roll_used[ 1 ] = 0;
-
- /* Compute the destinations. White moves in a negative */
- /* direction, Black moves in a positive direction. */
- /* Both must be within range... Source must be occupied */
-
- for( i = 0; i < s_val; i++ )
- {
-
- /* is that really what the user rolled? */
-
- if ( ( dist[ i ] != die_1 ) &&
- ( dist[ i ] != die_2 ) )
- {
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "You rolled a %d and %d, not a %d!", die_1, die_2, dist[ i ] );
- return( FALSE );
- }
- else
- {
-
- /* Ok, Sure, that's what he rolled, but */
- /* you cant use one die twice... */
-
- if ( dist[ i ] == die_1 )
- roll_used[ 0 ]++;
- else
- roll_used[ 1 ]++;
-
- if ( die_1 == die_2 )
- j = 4;
- else
- j = 1;
-
- if ( ( roll_used[ 0 ] > j ) ||
- ( roll_used[ 1 ] > j ) )
- {
-
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "You've used the roll incorrectly. Try again." );
- return( FALSE );
-
- } /* too many! */
-
- } /* he rolled that */
-
- /* is there a man there? */
-
- if ( ( start[ i ] >= 0 ) &&
- ( start[ i ] <= 25 ) )
- if ( ! test[ start[ i ] ][ me ] )
- {
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "There is no %s player at %d.", NAME, start[ i ] );
- return( FALSE );
- }
-
- /* if that was ok, compute target and test it */
-
- if ( me == WHITE )
- {
-
- /* if we are moving off the board, is it ok? */
-
- if ( ( ( target[ i ] = start[ i ] - dist[ i ] ) < 1 ) &&
- ( start[ i ] != BAR ) )
- if ( ! w_exit_ok( test, start[ i ], dist[ i ] ) )
- {
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "White can not exit the board yet." );
- return( FALSE );
- }
- }
-
- else
- {
-
- /* same here - if going off, is it valid? */
-
- if ( ( ( target[ i ] = start[ i ] + dist[ i ] ) > 24 ) &&
- ( start[ i ] != BAR ) )
- if ( ! b_exit_ok( test, start[ i ], dist[ i ] ) )
- {
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "Black can not exit the board yet." );
- return( FALSE );
- }
- }
-
- /* do the bad guys live there? */
-
- if ( ( target[ i ] > 0 ) &&
- ( target[ i ] < 25 ) &&
- ( test[ target[ i ] ][ OTHER ] > 1 ) )
- {
- /* too many enemies there, we can't move it */
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "Point %d is not occupied by %s.", target[ i ], NAME );
- return( FALSE );
- }
-
- /* are we making a move with men on the bar? */
-
- if ( ( start[ i ] != BAR ) &&
- ( test[ BAR ][ me ] ) )
- {
- char_at( X_INFO, Y_INFO, CTEOL, TEXT_COLOR );
- printf( "You canna do that! You have players on the bar!" );
- return( FALSE );
- }
-
- /* if it passed all of these, move the guy! */
-
- test[ start[ i ] ][ me ]--;
-
- if ( ( target[ i ] > 0 ) &&
- ( target[ i ] < 25 ) )
- {
- test[ target[ i ] ][ me ]++;
- /* did we bump somebody? */
- if ( test[ target[ i ] ][ OTHER ] )
- test[ target[ i ] ][ OTHER ] = 0;
- }
-
- } /* checking */
-
- /* otherwise, it is ok */
-
- for( i = 0; i < s_val; i++ )
- {
-
- /* move the old piece off first, or you */
- /* will blank out the guy that should */
- /* be at that position. */
-
- if ( ( target[ i ] > 0 ) &&
- ( target[ i ] < 25 ) &&
- ( board[ target[ i ] ][ OTHER ] ) )
- move_piece( target[ i ], OTHER_BAR, OTHER, side );
-
- move_piece( start[ i ], target[ i ], me, side );
-
- } /* move all of them. */
-
- } /* handle_command */
-
- /*P*/
- /****************************************************************/
- /* */
- /* can_move */
- /* */
- /* This routine looks at the board for special conditions - if */
- /* black has a man off, for example, but all of the points are */
- /* covered by white, then black can not even move. */
- /* */
- /****************************************************************/
-
- can_move( who )
-
- int who;
-
- {
-
- int i;
-
- if ( who == BLACK )
- {
-
- if ( board[ B_BAR ][ BLACK ] )
- {
-
- for( i = 1; i < 7; i++ )
- if ( board[ i ][ WHITE ] < 2 )
- return( TRUE );
- return( FALSE );
-
- }
- }
- else
- {
-
- if ( board[ W_BAR ][ WHITE ] )
- {
-
- for( i = 24; i > 18; i-- )
- if ( board[ i ][ BLACK ] < 2 )
- return( TRUE );
- return( FALSE );
-
- }
- }
-
- return( TRUE );
-
- } /* can_move */